package org.fisco.bcos.sdk.demo.contract;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.v3.client.Client;
import org.fisco.bcos.sdk.v3.codec.datatypes.Bool;
import org.fisco.bcos.sdk.v3.codec.datatypes.Function;
import org.fisco.bcos.sdk.v3.codec.datatypes.Type;
import org.fisco.bcos.sdk.v3.codec.datatypes.TypeReference;
import org.fisco.bcos.sdk.v3.codec.datatypes.Utf8String;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.Int32;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple1;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.v3.contract.Contract;
import org.fisco.bcos.sdk.v3.crypto.CryptoSuite;
import org.fisco.bcos.sdk.v3.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.v3.model.CryptoType;
import org.fisco.bcos.sdk.v3.model.TransactionReceipt;
import org.fisco.bcos.sdk.v3.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException;

@SuppressWarnings("unchecked")
public class KVTableTest extends Contract {
    public static final String[] BINARY_ARRAY = {
        "608060405234801561001057600080fd5b50600080546001600160a01b03191661100290811790915560408051808201825260098152681d17dadd97dd195cdd60ba1b6020820152905163b0e89adb60e01b815263b0e89adb91610065916004016101aa565b6020604051808303816000875af1158015610084573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100a89190610202565b506000805460408051808201825260098152681d17dadd97dd195cdd60ba1b6020820152905163f23f63c960e01b81526001600160a01b039092169163f23f63c9916100f69160040161022c565b602060405180830381865afa158015610113573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610137919061023f565b600180546001600160a01b0319166001600160a01b039290921691909117905550610268565b6000815180845260005b8181101561018357602081850181015186830182015201610167565b81811115610195576000602083870101525b50601f01601f19169290920160200192915050565b6060815260006101bd606083018461015d565b82810380602085015260038252626b657960e81b602083015260408101604085015250600560408201526476616c756560d81b60608201526080810191505092915050565b60006020828403121561021457600080fd5b81518060030b811461022557600080fd5b9392505050565b602081526000610225602083018461015d565b60006020828403121561025157600080fd5b81516001600160a01b038116811461022557600080fd5b6104a0806102776000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b51614610065575b600080fd5b61004e61004936600461025d565b61008b565b60405161005c9291906102ee565b60405180910390f35b610078610073366004610309565b610116565b60405160039190910b815260200161005c565b60015460405163349f642f60e11b8152600091606091839183916001600160a01b039091169063693ec85e906100c590889060040161036d565b600060405180830381865afa1580156100e2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261010a9190810190610387565b90969095509350505050565b6001546040516374a15a8b60e11b815260009182916001600160a01b039091169063e942b5169061014d9087908790600401610419565b6020604051808303816000875af115801561016c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101909190610447565b949350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156101d7576101d7610198565b604052919050565b600067ffffffffffffffff8211156101f9576101f9610198565b50601f01601f191660200190565b600082601f83011261021857600080fd5b813561022b610226826101df565b6101ae565b81815284602083860101111561024057600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561026f57600080fd5b813567ffffffffffffffff81111561028657600080fd5b61019084828501610207565b60005b838110156102ad578181015183820152602001610295565b838111156102bc576000848401525b50505050565b600081518084526102da816020860160208601610292565b601f01601f19169290920160200192915050565b821515815260406020820152600061019060408301846102c2565b6000806040838503121561031c57600080fd5b823567ffffffffffffffff8082111561033457600080fd5b61034086838701610207565b9350602085013591508082111561035657600080fd5b5061036385828601610207565b9150509250929050565b60208152600061038060208301846102c2565b9392505050565b6000806040838503121561039a57600080fd5b825180151581146103aa57600080fd5b602084015190925067ffffffffffffffff8111156103c757600080fd5b8301601f810185136103d857600080fd5b80516103e6610226826101df565b8181528660208385010111156103fb57600080fd5b61040c826020830160208601610292565b8093505050509250929050565b60408152600061042c60408301856102c2565b828103602084015261043e81856102c2565b95945050505050565b60006020828403121561045957600080fd5b81518060030b811461038057600080fdfea26469706673582212205da76511476b58eee8531a49c6fae26b17d147bbd97fb517b8377985ee0e7d9e64736f6c634300080b0033"
    };

    public static final String BINARY =
            org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", BINARY_ARRAY);

    public static final String[] SM_BINARY_ARRAY = {
        "608060405234801561001057600080fd5b50600080546001600160a01b03191661100290811790915560408051808201825260098152681d17dadd97dd195cdd60ba1b602082015290516394558dab60e01b81526394558dab91610065916004016101aa565b6020604051808303816000875af1158015610084573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100a89190610202565b506000805460408051808201825260098152681d17dadd97dd195cdd60ba1b602082015290516359a48b6560e01b81526001600160a01b03909216916359a48b65916100f69160040161022c565b602060405180830381865afa158015610113573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610137919061023f565b600180546001600160a01b0319166001600160a01b039290921691909117905550610268565b6000815180845260005b8181101561018357602081850181015186830182015201610167565b81811115610195576000602083870101525b50601f01601f19169290920160200192915050565b6060815260006101bd606083018461015d565b82810380602085015260038252626b657960e81b602083015260408101604085015250600560408201526476616c756560d81b60608201526080810191505092915050565b60006020828403121561021457600080fd5b81518060030b811461022557600080fd5b9392505050565b602081526000610225602083018461015d565b60006020828403121561025157600080fd5b81516001600160a01b038116811461022557600080fd5b61049c806102776000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80631a391cb41461003b5780637b1b8e0314610066575b600080fd5b61004e610049366004610259565b610087565b60405160039190910b81526020015b60405180910390f35b6100796100743660046102bd565b610109565b60405161005d92919061034e565b60015460405163068e472d60e21b815260009182916001600160a01b0390911690631a391cb4906100be9087908790600401610369565b6020604051808303816000875af11580156100dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101019190610397565b949350505050565b600154604051637b1b8e0360e01b8152600091606091839183916001600160a01b0390911690637b1b8e03906101439088906004016103c1565b600060405180830381865afa158015610160573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261018891908101906103d4565b90969095509350505050565b63b95aa35560e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156101d3576101d3610194565b604052919050565b600067ffffffffffffffff8211156101f5576101f5610194565b50601f01601f191660200190565b600082601f83011261021457600080fd5b8135610227610222826101db565b6101aa565b81815284602083860101111561023c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561026c57600080fd5b823567ffffffffffffffff8082111561028457600080fd5b61029086838701610203565b935060208501359150808211156102a657600080fd5b506102b385828601610203565b9150509250929050565b6000602082840312156102cf57600080fd5b813567ffffffffffffffff8111156102e657600080fd5b61010184828501610203565b60005b8381101561030d5781810151838201526020016102f5565b8381111561031c576000848401525b50505050565b6000815180845261033a8160208601602086016102f2565b601f01601f19169290920160200192915050565b82151581526040602082015260006101016040830184610322565b60408152600061037c6040830185610322565b828103602084015261038e8185610322565b95945050505050565b6000602082840312156103a957600080fd5b81518060030b81146103ba57600080fd5b9392505050565b6020815260006103ba6020830184610322565b600080604083850312156103e757600080fd5b825180151581146103f757600080fd5b602084015190925067ffffffffffffffff81111561041457600080fd5b8301601f8101851361042557600080fd5b8051610433610222826101db565b81815286602083850101111561044857600080fd5b6104598260208301602086016102f2565b809350505050925092905056fea264697066735822122020635f6a5bb4eb46b45ed657e1293ba6f812aeaaa995ae6bb159129719d6739364736f6c634300080b0033"
    };

    public static final String SM_BINARY =
            org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);

    public static final String[] ABI_ARRAY = {
        "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"conflictFields\":[{\"kind\":3,\"slot\":0,\"value\":[0]}],\"inputs\":[{\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"selector\":[1765722206,2065403395],\"stateMutability\":\"view\",\"type\":\"function\"},{\"conflictFields\":[{\"kind\":3,\"slot\":0,\"value\":[0]}],\"inputs\":[{\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"item_name\",\"type\":\"string\"}],\"name\":\"set\",\"outputs\":[{\"internalType\":\"int32\",\"name\":\"\",\"type\":\"int32\"}],\"selector\":[3913463062,439950516],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
    };

    public static final String ABI = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", ABI_ARRAY);

    public static final String FUNC_GET = "get";

    public static final String FUNC_SET = "set";

    protected KVTableTest(String contractAddress, Client client, CryptoKeyPair credential) {
        super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
    }

    public static String getBinary(CryptoSuite cryptoSuite) {
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
    }

    public static String getABI() {
        return ABI;
    }

    public Tuple2<Boolean, String> get(String id) throws ContractException {
        final Function function =
                new Function(
                        FUNC_GET,
                        Arrays.<Type>asList(new Utf8String(id)),
                        Arrays.<TypeReference<?>>asList(
                                new TypeReference<Bool>() {}, new TypeReference<Utf8String>() {}));
        List<Type> results = executeCallWithMultipleValueReturn(function);
        return new Tuple2<Boolean, String>(
                (Boolean) results.get(0).getValue(), (String) results.get(1).getValue());
    }

    public TransactionReceipt set(String id, String item_name) {
        final Function function =
                new Function(
                        FUNC_SET,
                        Arrays.<Type>asList(new Utf8String(id), new Utf8String(item_name)),
                        Collections.<TypeReference<?>>emptyList(),
                        4);
        return executeTransaction(function);
    }

    public String set(String id, String item_name, TransactionCallback callback) {
        final Function function =
                new Function(
                        FUNC_SET,
                        Arrays.<Type>asList(new Utf8String(id), new Utf8String(item_name)),
                        Collections.<TypeReference<?>>emptyList(),
                        4);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForSet(String id, String item_name) {
        final Function function =
                new Function(
                        FUNC_SET,
                        Arrays.<Type>asList(new Utf8String(id), new Utf8String(item_name)),
                        Collections.<TypeReference<?>>emptyList(),
                        4);
        return createSignedTransaction(function);
    }

    public Tuple2<String, String> getSetInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function =
                new Function(
                        FUNC_SET,
                        Arrays.<Type>asList(),
                        Arrays.<TypeReference<?>>asList(
                                new TypeReference<Utf8String>() {},
                                new TypeReference<Utf8String>() {}));
        List<Type> results =
                this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple2<String, String>(
                (String) results.get(0).getValue(), (String) results.get(1).getValue());
    }

    public Tuple1<BigInteger> getSetOutput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getOutput();
        final Function function =
                new Function(
                        FUNC_SET,
                        Arrays.<Type>asList(),
                        Arrays.<TypeReference<?>>asList(new TypeReference<Int32>() {}));
        List<Type> results =
                this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<BigInteger>((BigInteger) results.get(0).getValue());
    }

    public static KVTableTest load(
            String contractAddress, Client client, CryptoKeyPair credential) {
        return new KVTableTest(contractAddress, client, credential);
    }

    public static KVTableTest deploy(Client client, CryptoKeyPair credential)
            throws ContractException {
        return deploy(
                KVTableTest.class,
                client,
                credential,
                getBinary(client.getCryptoSuite()),
                getABI(),
                null,
                null);
    }
}
